/*
 * Created by SharpDevelop.
 * User: Evaldas
 * Date: 2008.04.28
 * Time: 18:46
 * 
 * Service Object
 * USB EXPERIMENT INTERFACE BOARD K8055
 */

#region Using 
using System;
using System.Threading;
using Microsoft.PointOfService;
using Microsoft.PointOfService.BasicServiceObjects;
#endregion

namespace Velleman.K8055
{
	/// <summary>
	/// Description of K8055Service.
	/// </summary>
	[ServiceObjectAttribute(DeviceType.Lights, "Velleman K8055", "Velleman USB Experiment Interface Board K8055", 1, 12)]
	public class K8055Service: LightsBasic
    {
        #region Private Member Variables

        private bool[] devs = {false, false, false, false};
		const int MAX_LIGTHTS = 8;

        #endregion

        #region Constructor
        /// <summary>
		/// Constructor
		/// </summary>
		public K8055Service()
		{					
		}
		#endregion
		
		#region Destrutor
		
		/// <summary>
		/// Finalizer
		/// </summary>
		~K8055Service()
		{
            K8055D.CloseDevice();
			Dispose(false);
		}
		
		#endregion
		
		#region UPOS Properties
		
		/// <summary>
		/// Gets the integer value that indicates the maximum number of lights that the device can support
		/// </summary>
		public override int MaxLights {
			get {
				return MAX_LIGTHTS; 
			}
		}
		
		/// <summary>
		/// Gets the property that indicates what colors the device supports
		/// </summary>
		public override LightColors CapColor {
			get {
				return LightColors.Primary;
			}
		}
		
		/// <summary>
		/// Gets the Boolean value that indicates if a blinking capability is supported
		/// </summary>
		public override bool CapBlink {
			get {
				return false;
			}
		}
		
		/// <summary>
		/// Gets the property that indicates if the device supports different alarms
		/// </summary>
		public override LightAlarms CapAlarm {
			get {
				return LightAlarms.None;
			}
		}
		
		private string checkhealthtext;
		public override string CheckHealthText
		{
			get
			{
				// Verify that device is open
				VerifyState(false, false);

				return checkhealthtext;
			}
		}
		
		#endregion
		
		#region UPOS Methods
		
		public override bool DeviceEnabled
		{
			// Device State checking done in base class

			get { return base.DeviceEnabled; }

			set 
			{
				if (value != base.DeviceEnabled)
				{
					// Call base class first because it will handle cases such as the
					// device isn't claimed etc.
					base.DeviceEnabled = value;
					
					// Stop reading from the device
					K8055D.CloseDevice();
					Logger.Info(this.DeviceName, "K8055D.CloseDevice()");
					
					// Start reading from the device
					if (value == true)					
					{
						try
						{
							int error = K8055D.OpenDevice(Int32.Parse(this.DevicePath));
							Logger.Info(this.DeviceName, string.Format("K8055D.OpenDevice({0}) Result={1}", this.DevicePath, error));
							// If succeeded the return value will be the card address read from the K8055 hardware.
							// Return value -1 indicates that K8055 card was not found
							if (error < 0)
								throw new PosControlException("K8055 card was not found", ErrorCode.Failure, error);
								
						}
						catch (Exception e)
						{
							// disable device
							base.DeviceEnabled = false;
						
							// rethrow PosControlExceptions
							if (e is PosControlException)
								throw;														

                            // Wrap other exceptions in PosControlExceptions
							throw new PosControlException("Unable To Enable Device: " + e.Message, ErrorCode.Failure, e);
						}
					}
				}
			}
		}
		
		/// <summary>
		/// Tests the state of a device
		/// External Performs a more thorough test that may change the device. For example, a pattern may be printed on the printer. 
		/// Interactive Performs an interactive test of the device. The supporting service object typically displays a modal dialog box to present test options and results. 
		/// Internal Performs a health check that does not physically change the device. The device is tested by internal tests to the extent possible. 
		/// </summary>
		/// <param name="level">Indicates the type of health check to be performed on the device. Possible values are defined by the HealthCheckLevel enumeration</param>
		/// <returns></returns>
		public override string CheckHealth(HealthCheckLevel level)
		{
			// Verify that device is open, claimed and enabled
			VerifyState(true, true);

			// TODO: check the health of the device and return a descriptive string 
			//K8055D.Version();

            switch (level)
            {
                case HealthCheckLevel.External:
                    ExternalCheckHealth();
                    break;
                case HealthCheckLevel.Interactive:
                    InteractForm inf = new InteractForm(this);
                    inf.ShowDialog();
                    break;
            }

			// Cache result in the CheckHealthText property
			checkhealthtext = "Ok";
			return checkhealthtext;
		}
		
		/// <summary>
		/// Switches on the specified light or lets it blink
		/// </summary>
		/// <param name="lightNumber">Specifies the light number. Valid light numbers are 1 through MaxLights</param>
		/// <param name="blinkOnCycle">A zero (0) value indicates no blink cycle. A positive value indicates the blink on cycle time in milliseconds. Negative values are not allowed</param>
		/// <param name="blinkOffCycle">A zero (0) value indicates no blink cycle. A positive value indicates the blink off cycle time in milliseconds. Negative values are not allowed</param>
		/// <param name="color">Specifies the color of the light, must be one of the colors defined by CapColor</param>
		/// <param name="alarm">Specifies the used alarm type, must be one of the alarms defined by CapAlarm</param>
		public override void SwitchOn(int lightNumber, int blinkOnCycle, int blinkOffCycle, LightColors color, LightAlarms alarm)
		{
			// Verify that device is open
			VerifyState(true, true);
			
			K8055D.SetDigitalChannel(lightNumber);	
			Logger.Info(this.DeviceName, string.Format("K8055D.SetDigitalChannel({0})", lightNumber));
		}
		
		/// <summary>
		/// Switches off the specified light
		/// </summary>
		/// <param name="lightNumber">Specifies the light number. Valid light numbers are 1 through MaxLights</param>
		public override void SwitchOff(int lightNumber)
		{
			// Verify that device is open
			VerifyState(true, true);
			
			K8055D.ClearDigitalChannel(lightNumber);	
			Logger.Info(this.DeviceName, string.Format("K8055D.ClearDigitalChannel({0})", lightNumber));
		}

		public override DirectIOData DirectIO( int command, int data, object obj )
		{
			// Verify that device is open
			VerifyState(false, false);
			
			return new DirectIOData(data, obj);
		}
		
		
		public override void Open()
		{
			// Device State checking done in base class
			base.Open();

			// Initialize the CheckHealthText property to an empty string
			checkhealthtext = "";
		    this.SearchDevices();
		}
		
		#endregion

        #region Private Methods

        private void SearchDevices()
        {
			int d = K8055D.SearchDevices();
			Logger.Info(this.DeviceName, string.Format("K8055D.SearchDevices() Result={0}", d));

            devs[0] = ((d & 1) != 0);
            devs[1] = ((d & 2) != 0);
            devs[2] = ((d & 4) != 0);
            devs[3] = ((d & 8) != 0);
            
/*
            if (devs[0])
                DevConnect(0);
            else if (devs[1])
                DevConnect(1);
            else if (devs[2])
                DevConnect(2);
            else if (devs[3])
                DevConnect(3);
            */

        }

        private void ExternalCheckHealth()
        {
            lock (this)
            {
            K8055D.ClearAllDigital();
            for (int i = 1; i <= 8; i++)
            {
                K8055D.SetDigitalChannel(i);
                Thread.Sleep(500);
                K8055D.ClearDigitalChannel(i);
            }
            }
        }

        #endregion
    }
}
